{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from collections import Counter\n",
    "import random\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.tests.test_multiclass import iris\n",
    "from sklearn.utils import shuffle\n",
    "plt.rcParams['figure.figsize'] = (10.0,8.0)\n",
    "plt.rcParams['image.interpolation'] = 'nearest'\n",
    "plt.rcParams['image.cmap'] = 'gray'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(105, 4)\n",
      "(45, 4)\n",
      "(105, 1)\n",
      "(45, 1)\n"
     ]
    }
   ],
   "source": [
    "X, y = shuffle(iris.data, iris.target, random_state=13)\n",
    "X = X.astype(np.float32)\n",
    "offset = int(X.shape[0] * 0.7)\n",
    "X_train, y_train = X[:offset], y[:offset]\n",
    "X_test, y_test = X[offset:], y[offset:]\n",
    "y_train = y_train.reshape((-1,1))\n",
    "y_test = y_test.reshape((-1,1))\n",
    "print(X_train.shape)\n",
    "print(X_test.shape)\n",
    "print(y_train.shape)\n",
    "print(y_test.shape)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [],
   "source": [
    "def compute_distances(X_test, X_train):\n",
    "    num_test = X_test.shape[0]\n",
    "    num_train = X_train.shape[1]\n",
    "    dists = np.zeros((num_test, num_train))\n",
    "    M = np.dot(X_test, X_train.T)\n",
    "    te = np.square(X_test).sum(axis=1)\n",
    "    tr = np.square(X_train).sum(axis=1)\n",
    "    te = te.reshape((-1,1))\n",
    "    dists = np.sqrt(-2 *M +tr + te)\n",
    "    return dists"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(45, 105)\n"
     ]
    }
   ],
   "source": [
    "dists = compute_distances(X_test,X_train)\n",
    "print(dists.shape)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 720x576 with 1 Axes>",
      "image/png": "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i2r7BupySZvU0/pIGpxzbi9pcN3fjTHGGGP+K5jhAirn/Iik+suyrSUNqPvzAEldf97bMsYYY4yZdfmxHqjmOefxklT3b/59Q1JKqWdKaUhKaUjppyFjjDHGmNmJX9xEnnPun3PumHPuSJtbGmOMMcbMbvzYBdSElFJLSar7N29JbIwxxhjzG+THlnIZJKmbpH51/761lqBGjRqpfhbefPPNh8dSFtyFF14YtL333hvjmzZtWpN20003YXyPHj2CRhlrZ511VtAuuOACPGfv3r2DRhkS/fv3x3jKcKD2K5WoOP3004O2zz77BO2www7DeMrwOOSQQ4K28sorYzyVEzn11FOD1rdv36CdccYZeM7dd989aG3btg1aaev//fffP2iHHnpo0EqlYBZffPGgUSZPKYuQ2v/kk08O2lFHHYXxVPKIxh9lPEmcxUqZiUcffXTQKAtMkq644oqgdevWLWilLLojjzwyaHvuuWfQKDNQ4jlhjz32CNraa6+N8dT/lEH6ySefYDxlAB977LFBO+aYY4J2xBFH4DmpT44//vig0Tsu8XtC2Zp/+9vfMJ4yM7faaqugUQakxO8kZcauttpqGE+ZXJTdduKJJ2I8zecDBw4MGn3GUMkaid/THXfcEY8l6D25+OKLg1b65ebss88O2imnnBI0+tyS+D0755xzgkZzjCS1bt06aNT/l112WdB22203PCdlYdJ1SpnulC1Na4muXbtifL9+/YI2aNAgPFaq4RuolNK1kp6UtHRKaVxKqYemL5y6pJRGSepS93djjDHGmP8KZvgNVM55p8J/2uBnvhdjjDHGmNkC70RujDHGGFMRL6CMMcYYYyoyw1IuPyeNGjXK9bfPf+655/BY2r592WWXDVppS3gyjA8dOjRom2++OcZTu9D28WQknTx5Mp6zZESuT8kEfv/99wftscceCxoZuyUup/DWW28FjYzRJR555JGglcox0POTifnVV18NWqnkzj333BM0un8qkSCxOfill14KWsm0uMgiiwSNzLmlcgrPP/980GicU8kciY3UVGKBnlNigyiZVmsdO5LUpUsX1Ovz7rvvok5tSibmUhknKqXy4IMPBq1nz54YP3z48KBREkDp+akMFWlUBormPYlLkbRr1y5ov//97zH+iSeeCBolpYwePRrjqWwNvWelZAUq+0Njj8qrSNIKK6wQ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qVrLjpTaia5PfV96pgUXXLCm65eoteQR9ZPEz0/PROVpJH7Par3/0nF0T0TJxE3GdnrPS9cnI3KVd780/upTGhO1jr/S9en5a+2nUskYKntSpVxYrfdfarvS+K3lOhK/k3T9kgmd+oquRe9OlX6u9T7/03nrU+Xz5D9Ry9FrSdpN0osppefrtCM1feE0MKXUQ9JYSTElwBhjjDHmN8gMF1A558cklao2bvDz3o4xxhhjzKyPdyI3xhhjjKmIF1DGGGOMMRWp5pj6iXz88ce65ZZbfqCtueaaeOz48eODRjtxl3bdfv7554O2xhprBO2+++7DeNrhnMy9jz76aNBod2lJGjJkSNDICLjaaqthfIsWLYJGz9SpUyeMf+6554JGO7I+8cQTGE9mvvPOOy9otJuuxDtXU5uccMIJQXvqqafwnLTDNY2TkhGTdnKnc7766qsY/+9//ztotOP9/PPPj/GHHnpo0GjX5379+mE8mYsHDRoUtFKyBI1pOiftDt+mTRs857333hs02jWbxnMpfuuttw5a6Zlo1+7zzz8/aH/6059qjqcd50eNGoXxrVq1Chq9k/fff3/QaGd+iduP5p5NN90U42k3azLcnnTSSRi/1VZbBe3uu+8OWsmEW+uu1aVdv19++eWgbbbZZkF7+umnMX7gwIFBe/jhh4NG82npM+rOO+8M2o033hi0UgIAzce0Y/paa62F8TQnHnnkkUErmdhvu+22oFHFge7du2M87fpN8yyNPfrckKRLL700aB988EHQJk2ahPFUReCdd94JWqkCCn32/Cf8DZQxxhhjTEW8gDLGGGOMqYgXUMYYY4wxFfECyhhjjDGmIl5AGWOMMcZUZKZm4TVp0kQ77bTTD7RnnnkGj23Xrl3QKGumlPHWvHnzoL3yyitBo2w7STrqqKOCNt988wVtm222qSlWkrbccsugUTmIUnYPZQc9++yzQaPMNknq1atX0CjrY/vteVP5Tz6JNaT32GOPoB122GEYv9BCCwWNsnt69+4dtA033BDP2bNnz6B17do1aFTKQeI+2W+//YK2zDLLYDxlZ1EmVNu2bTGejt1kk02CVmpTKg9EmZWlLMD3338/aJS1Q+8JXVuSdt5556AdffTRQaPxJEm77LJL0E455ZSgURaXJG2wQdzft0ePHkGjbEVJYY6SpJYtWwZtwoQJGN+0adOg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6d2luYOek94die+frk/JPxL3P70npR2qyURP7wTNsfRZJPGz0jlLiVI0fuj6VRJAKL4091BbUXzbtm0xnnaCpzahz5OSsZ3eSWq/UlIOfUbR52np86T02VfC30AZY4wxxlTECyhjjDHGmIp4AWWMMcYYUxEvoIwxxhhjKjLDBVRKaZ6U0jMppRdSSiNSSn+v0/umlN5JKT1f989mv/ztGmOMMcb8+iTK4vnBAdPt6vPnnD9LKTWQ9JikAyVtIumznPNptV6sTZs2+ZhjjvmBRiUeJM7wOeOMM4J24IEHYnyzZs2CRuUUHnroIYyvf58SZw7su+++NcVK0hFHHBE0ykx7/fXXMf6+++4L2tChQ4O29957Y3zv3r2DtvHGGwft/PPPx3jK0OjRo0fQqESFxKUHdt9996AdfPDBQevbty+ek55pscUWC1opY+roo48O2l577RU0ykKSpMUXXzxo+++/f9CWWGIJjN90002Ddvrppwft8MMPx3jqk0GDBgWtlF1C2U2USbPbbrsFrZQxds899wTtyCOPDFopW/TCCy8MGr1TpewoGhO77rpr0HbYYQeM33HHHYPWqlWroL333nsY37Rp06Cde+65Qdtuu+2Cdumll+I5hw0bFrSzzjoraNT2krT55psHjTLj6J4kadSoUUHbYIMNglbqE4qnz54VV1wR49u0aRO0hx9+OGj9+/fHeOrrwYMHB+22224L2i233ILnPOWUU4K28847B62UMXbrrbcG7e9//3vQhg8fjvEDBgwIGo39Uhms4447LmgnnXRS0B577DGMp/mcMmvpc2v99dfHc6600kpBo+x5urbE44zi6X2Q+D3t1q3b0JxzRzp+htsY5Omj/Lvc1gZ1//znVZcxxhhjzG+YmjxQKaU5UkrPS5oo6b6c89N1/6lXSml4SunSlBJWcUwp9UwpDUkpDaH/WzbGGGOMmd2oaQGVc56ac15Z0qKSOqWUlpd0gaR2klaWNF5S/N1hemz/nHPHnHPH0s8gxhhjjDGzE5Wy8HLOH0t6SNImOecJdQuraZIultTp5789Y4wxxphZj1pM5E0lTck5f5xSmlfSvZL+IWloznl83TEHSVoj5xzdl9+jQYMGuf629GTwkqSJEycG7S9/+UvQSqZBKvOw/PLLB22rrbbCeDJSk+mSzLVkApakgw46CPX6vPXWW6jffffd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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(dists, interpolation='none')\n",
    "plt.show()\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [],
   "source": [
    "def predict_labels(y_train, dists, k=1):\n",
    "    num_test = dists.shape[0]\n",
    "    y_pred = np.zeros(num_test)\n",
    "    for i in range(num_test):\n",
    "\n",
    "        closest_y = []\n",
    "        labels = y_train[np.argsort(dists[i,:])].flatten()\n",
    "        closest_y = labels[0:k]\n",
    "\n",
    "        c = Counter(closest_y)\n",
    "        y_pred[i] = c.most_common(1)[0][0]\n",
    "    return y_pred\n",
    "\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Got 45 / 45 correct => accuracy: 1.000000\n"
     ]
    }
   ],
   "source": [
    "y_test_pred = predict_labels(y_train, dists, k=1)\n",
    "y_test_pred = y_test_pred.reshape((-1, 1))\n",
    "num_correct = np.sum(y_test_pred == y_test)\n",
    "accuracy = float(num_correct) / X_test.shape[0]\n",
    "print('Got %d / %d correct => accuracy: %f' % (num_correct, X_test.shape[0], accuracy))\n",
    "\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "only integer scalar arrays can be converted to a scalar index",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
      "\u001B[1;32m<ipython-input-9-bd17a7669f0d>\u001B[0m in \u001B[0;36m<module>\u001B[1;34m\u001B[0m\n\u001B[0;32m     15\u001B[0m         \u001B[1;31m# 计算距离\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m     16\u001B[0m         \u001B[0mtemp_dists\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mcompute_distances\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mvalidation_X_test\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mT\u001B[0m\u001B[1;33m,\u001B[0m\u001B[0mvalidation_y_test\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mT\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m---> 17\u001B[1;33m         \u001B[0mtemp_y_test_pred\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mpredict_labels\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0my_train_folds\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mtemp_dists\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mk\u001B[0m\u001B[1;33m=\u001B[0m\u001B[0mk\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m     18\u001B[0m         \u001B[0mtemp_y_test_pred\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mtemp_y_test_pred\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mreshape\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m-\u001B[0m\u001B[1;36m1\u001B[0m\u001B[1;33m,\u001B[0m\u001B[1;36m1\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m     19\u001B[0m         \u001B[1;31m# 查看分类准确率\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;32m<ipython-input-7-b960ab8f2d22>\u001B[0m in \u001B[0;36mpredict_labels\u001B[1;34m(y_train, dists, k)\u001B[0m\n\u001B[0;32m      5\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m      6\u001B[0m         \u001B[0mclosest_y\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;33m[\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m----> 7\u001B[1;33m         \u001B[0mlabels\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0my_train\u001B[0m\u001B[1;33m[\u001B[0m\u001B[0mnp\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0margsort\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mdists\u001B[0m\u001B[1;33m[\u001B[0m\u001B[0mi\u001B[0m\u001B[1;33m,\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mflatten\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m      8\u001B[0m         \u001B[0mclosest_y\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mlabels\u001B[0m\u001B[1;33m[\u001B[0m\u001B[1;36m0\u001B[0m\u001B[1;33m:\u001B[0m\u001B[0mk\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m      9\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;31mTypeError\u001B[0m: only integer scalar arrays can be converted to a scalar index"
     ]
    }
   ],
   "source": [
    "num_folds = 5\n",
    "k_choices = [1,3,5,8,10,12,15,20,50,100]\n",
    "\n",
    "X_train_folds = []\n",
    "y_train_folds = []\n",
    "X_train_folds = np.array_split(X_train,num_folds)\n",
    "y_train_folds = np.array_split(y_train,num_folds)\n",
    "k_to_accuracies = {}\n",
    "for k in k_choices:\n",
    "    for fold in range(num_folds):\n",
    "        validation_X_test = X_train_folds[fold]\n",
    "        validation_y_test = y_train_folds[fold]\n",
    "        temp_X_train = np.concatenate(X_train_folds[:fold] + X_train_folds[fold+1:])\n",
    "        temp_y_train = np.concatenate(y_train_folds[:fold] + y_train_folds[fold+1:])\n",
    "        # 计算距离\n",
    "        temp_dists = compute_distances(validation_X_test.T,validation_y_test.T)\n",
    "        temp_y_test_pred = predict_labels(y_train_folds, temp_dists, k=k)\n",
    "        temp_y_test_pred = temp_y_test_pred.reshape((-1,1))\n",
    "        # 查看分类准确率\n",
    "        num_correct = np.sum(temp_y_test_pred == validation_X_test)\n",
    "        num_test = validation_X_test.shape[0]\n",
    "        accuracy = float(num_correct) / num_test\n",
    "        k_to_accuracies[k] = k_to_accuracies.get(k,[]) + [accuracy]\n",
    "\n",
    "# 打印不同k值\n",
    "for k in sorted(k_to_accuracies):\n",
    "    for accuracy in k_to_accuracies[k]:\n",
    "        print('k = %d, accuracy = %f' % (k, accuracy))\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}